/* 
 *  Syntelos XB
 *  Copyright (C) 2006 John Pritchard.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License as
 *  published by the Free Software Foundation; either version 2 of
 *  the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307 USA
 */

package syntelos.xb;

/** 
 * <h3>XB assembler and disassembler</h3>
 * 
 * <p> Command line tool (filter) to assemble or disassemble a class file. </p>
 * 
 * <h3>Command line usage</h3>
 * 
 * <h4>Pipeline filter</h4>
 * 
 * <p> Pipe input into this command line filter and direct output into
 * a file.  The following usage pattern describes disassembling a
 * class file into XB format.
 * 
 * <pre>
 *    syntelos.xb.Main  das  &lt; foo.class &gt; foo.xml
 * </pre>
 * 
 * Note the disassembly command, "das" which is input literally as
 * shown as the only argument to the program.  And the following usage
 * pattern describes assembling a class file from XB format input.
 * 
 * <pre>
 *    syntelos.xb.Main  bas  &lt; foo.xml &gt; foo.class
 * </pre>
 * 
 * The assembly command to the program is "bas", as shown.
 * </p>
 * 
 * <h4>File arguments</h4>
 * 
 * <p> Supply input and output file arguments to this command line
 * program.  The following usage pattern describes disassembling a
 * class file into XB format.
 * 
 * <pre>
 *    syntelos.xb.Main  das  foo.class  foo.xml
 * </pre>
 * 
 * Note the disassembly command, "das" which is input literally as
 * shown as the only argument to the program.  The input is a class
 * file in the second argument, and the output is an xml file in the
 * third argument. </p>
 * 
 * <p> The following usage pattern describes assembling a class file
 * from XB format input.
 * 
 * <pre>
 *    syntelos.xb.Main  bas  foo.xml  foo.class
 * </pre>
 * 
 * The assembly command to the program is "bas", as shown.  The input
 * is an xml file in the second argument, and the output is a class
 * file in the third argument.   </p>
 * 
 * <p> Note that for both assembly and disassembly the third or output
 * file name can be omitted to default to the standard output as for
 * the pipeline usage described above. </p>
 * 
 * 
 * @see syntelos.xb.Class#readCF(syntelos.xb.IO$Uri,CF$Reader)
 * @see syntelos.xb.Class#readXB(syntelos.xb.IO$Uri,java.io.InputStream)
 * @see syntelos.xb.Class#writeCF(syntelos.xb.IO$Uri,CF$Writer)
 * @see syntelos.xb.Class#writeXB(syntelos.xb.IO$Uri,java.io.OutputStream)
 * 
 * 
 * @author John Pritchard (jdp@syntelos.com)
 */
public class Main {

    public static void usage(){
        System.err.println("Usage");
        System.err.println();
        System.err.println("   syntelos.xb.Main  das  < foo.class > foo.xml");
        System.err.println("   syntelos.xb.Main  das    foo.class   foo.xml");
        System.err.println();
        System.err.println("   syntelos.xb.Main  bas  < foo.xml > foo.class");
        System.err.println("   syntelos.xb.Main  bas    foo.xml   foo.class");
        System.err.println();
        System.err.println("   syntelos.xb.Main   pp  < foo.xml > foo.xml  ");
        System.err.println("   syntelos.xb.Main   pp    foo.xml   foo.xml  ");
        System.err.println();
        System.err.println("Description");
        System.err.println();
        System.err.println("   Assemble a class file from XB input using ");
        System.err.println("   the 'bas' command.  Or disassemble a class");
        System.err.println("   file to XB output using the 'das' command. ");
        System.err.println("   Pretty print with 'pp'.");
        System.err.println();
        System.err.println("   Works on stdio as a filter, or directly on ");
        System.err.println("   files.  Arguments are positional, required");
        System.err.println("   in order (command, input, output) with the  ");
        System.err.println("   output defaulting to console output, and the ");
        System.err.println("   input defaulting to console input.");
        System.err.println();
        System.exit(1);
    }

    /**
     * Reads a class file from <code>System.in</code>, and writes HCI
     * XB code to <code>System.out</code>.
     */
    public static void main (String[] argv){
        if (null == argv || 1 > argv.length)
            usage();
        else {
            int argc = argv.length;
            String call = argv[0], src = "stdio:in", dst = "stdio:out";
            java.io.InputStream in = System.in;
            java.io.OutputStream out = System.out;
            if (1 < argc){
                String test = argv[1];
                try {
                    java.io.File test_file = new java.io.File(test);
                    in = new java.io.FileInputStream(test_file);
                    src = "file:"+test;
                }
                catch (java.io.IOException iox){
                    System.err.println("Error opening input file '"+test+"'.");
                    System.exit(1);
                }
                if (2 < argc){
                    test = argv[2];
                    try {
                        java.io.File test_file = new java.io.File(test);
                        out = new java.io.FileOutputStream(test_file);
                        dst = "file:"+test;
                    }
                    catch (java.io.IOException iox){
                        System.err.println("Error opening output file '"+test+"'.");
                        System.exit(1);
                    }
                }
            }
            IO.Uri src_uri = new IO.Uri(src);
            IO.Uri dst_uri = new IO.Uri(dst);

            syntelos.xb.Class ctype = new syntelos.xb.Class();

            if ("das".equals(call)){
                /*
                 * disassemble
                 */
                try {
                    /*
                     * Read tree
                     */
                    CF.Reader reader = new CF.Reader.Stream(in);
                    ctype.readCF(src_uri,reader);
                }
                catch (java.io.IOException iox){
                    System.err.println("Error reading input from '"+src+"'.");
                    iox.printStackTrace();
                    System.exit(1);
                }
                catch (Error err){
                    System.err.println("Error in input from '"+src+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                catch (java.lang.Throwable err){
                    System.err.println("Error in input from '"+src+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                /*
                 * Decompile tree
                 */
                try {
                    syntelos.iou.dom.rw.Process decompiler = 
                        new syntelos.iou.dom.rw.Process(ctype);
                    syntelos.iou.dom.rw.Context context =
                        new syntelos.iou.dom.rw.Context.Document();
                    while (decompiler.decompile(context));
                }
                catch (java.io.IOException iox){
                    System.err.println("Error compiling input from '"+src+"'.");
                    iox.printStackTrace();
                    System.exit(1);
                }
                /*
                 * Write tree
                 */
                try {
                    ctype.writeXB(dst_uri,out);
                }
                catch (java.io.IOException iox){
                    System.err.println("Error writing output to '"+dst+"'.");
                    iox.printStackTrace();
                    System.exit(1);
                }
                catch (Error err){
                    System.err.println("Error in output to '"+dst+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                catch (java.lang.Throwable err){
                    System.err.println("Error in output to '"+dst+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                try {
                    out.flush();
                    in.close();
                    out.close();
                }
                catch (java.io.IOException iox){
                }
                System.exit(0);
            }
            else if ("bas".equals(call)){
                /*
                 * byte code assemble
                 */
                try {
                    ctype.destroy();
                    /*
                     * Read tree
                     */
                    ctype = ctype.readXB(src_uri,in);
                }
                catch (java.io.IOException iox){
                    System.err.println("Error reading input from '"+src+"'.");
                    iox.printStackTrace();
                    System.exit(1);
                }
                catch (Error err){
                    System.err.println("Error in input from '"+src+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                catch (java.lang.Throwable err){
                    System.err.println("Error in input from '"+src+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                try {
                    /*
                     * Compile tree
                     */
                    syntelos.iou.dom.rw.Process compiler = 
                        new syntelos.iou.dom.rw.Process(ctype);
                    syntelos.iou.dom.rw.Context context =
                        new syntelos.iou.dom.rw.Context.Document();

                    while (compiler.compile(context));
                }
                catch (java.io.IOException iox){
                    System.err.println("Error compiling input from '"+src+"'.");
                    iox.printStackTrace();
                    System.exit(1);
                }
                try {
                    /*
                     * Write tree
                     */
                    CF.Writer writer = new CF.Writer.Stream(out);
                    ctype.writeCF(dst_uri,writer);
                }
                catch (java.io.IOException iox){
                    System.err.println("Error writing output to '"+dst+"'.");
                    iox.printStackTrace();
                    System.exit(1);
                }
                catch (Error err){
                    System.err.println("Error in output to '"+dst+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                catch (java.lang.Throwable err){
                    System.err.println("Error in output to '"+dst+"'.");
                    err.printStackTrace();
                    System.exit(1);
                }
                try {
                    out.flush();
                    in.close();
                    out.close();
                }
                catch (java.io.IOException iox){
                }
                System.exit(0);
            }
            else if ("pp".equals(call)){
                /*
                 * Pretty print
                 */
                ctype.destroy();
                syntelos.iou.dom.Document doc = new syntelos.iou.dom.impl.Document();
                try {
                    /*
                     * Read
                     */
                    syntelos.iou.dom.Builder.Parser.Parse(in,doc,src);
                }
                catch (java.io.IOException iox){
                    System.err.println("Error reading input from '"+src+"': "+iox.getMessage());
                    try {
                        in.close();
                        out.close();
                    }
                    catch (java.io.IOException ignore){}
                    System.exit(1);
                }
                catch (org.xml.sax.SAXException sax){
                    System.err.println("Error parsing input from '"+src+"': "+sax.getMessage());
                    try {
                        in.close();
                        out.close();
                    }
                    catch (java.io.IOException ignore){}
                    System.exit(1);
                }
                try {
                    /*
                     * Write
                     */
                    syntelos.iou.dom.Formatter.User.Write(doc,out);
                }
                catch (java.io.IOException iox){
                    System.err.println("Error writing output to '"+dst+"': "+iox.getMessage());
                    try {
                        in.close();
                        out.close();
                    }
                    catch (java.io.IOException ignore){}
                    System.exit(1);
                }
                finally {
                    try {
                        out.flush();
                        in.close();
                        out.close();
                    }
                    catch (java.io.IOException ignore){
                    }
                }
                System.exit(0);
            }
            else
                usage();
        }
    }

}
